#pragma once

#include <Windows.h>
#include <Commctrl.h>
#include "win_base.h"
#include "win_frame.h"
#include "../scintilla/scintilla.h"
#include "../scintilla/SciLexer.h"


#define SCI_CMD(msg, wparam, lparam) _scFunc(_scPtr, msg, (int)(wparam), (int)(lparam)) 

class win_scintilla : public win_tile, public win_base
{
public:
    win_scintilla();
    ~win_scintilla();

    virtual bool reg_class(HINSTANCE hInstance = NULL, PTCHAR pszClassName = NULL);
    virtual bool create(HWND hWndParent = NULL);

public:
    // Text retrieval and modification
    int allocate(int nBytes){ return SCI_CMD(SCI_ALLOCATE, nBytes, 0); }
    int add_text(int nLength, const char* pszText) { return SCI_CMD(SCI_ADDTEXT, nLength, pszText); }
    int add_styled_text(int nLength, const char* pszText) { return SCI_CMD(SCI_ADDSTYLEDTEXT, nLength, pszText); }
    int append_text(int nLength, const char* pszText) { return SCI_CMD(SCI_APPENDTEXT, nLength, pszText); }
    int delete_range(int nPos, int nLength) { return SCI_CMD(SCI_DELETERANGE, nPos, nLength); }
    int clear_all() { return SCI_CMD(SCI_CLEARALL, 0, 0); }
    int clear_doc_style() { return SCI_CMD(SCI_CLEARDOCUMENTSTYLE, 0, 0); }
    int get_char_at(int nPos) { return SCI_CMD(SCI_GETCHARAT, nPos, 0); }
    int get_line(int nLine, char* pszText) { return SCI_CMD(SCI_GETLINE, nLine, pszText); }
    int get_read_only() { return SCI_CMD(SCI_GETREADONLY, 0, 0); }
    int get_style_at(int nPos) { return SCI_CMD(SCI_GETSTYLEAT, nPos, 0); }
    int get_style_bits() { return SCI_CMD(SCI_GETSTYLEBITS, 0, 0); }
    int get_styled_text(TextRange* ptrTextRange) { return SCI_CMD(SCI_GETSTYLEDTEXT, 0, ptrTextRange); }
    int get_text(int nLength, char* pszText) { return SCI_CMD(SCI_GETTEXT, nLength, pszText); }
    int get_text_rang(TextRange* ptrTextRange) { return SCI_CMD(SCI_GETTEXTRANGE, 0, ptrTextRange); }
    int insert_text(int nPos, const char* pszText) { return SCI_CMD(SCI_INSERTTEXT, nPos, pszText); }
    int replase_sel(const char* pszText) { return SCI_CMD(SCI_REPLACESEL, 0, pszText); }
    int set_read_only(bool bReadonly) { return SCI_CMD(SCI_SETREADONLY, bReadonly, 0); }
    int set_save_point() { return SCI_CMD(SCI_SETSAVEPOINT, 0, 0); }
    int set_style_bits(int nBits) { return SCI_CMD(SCI_SETSTYLEBITS, nBits, 0); }
    int set_text(char* pszText) { return SCI_CMD(SCI_SETTEXT, 0, pszText); }


    // Unicode support
    int target_as_utf8(char* pszText) { return SCI_CMD(SCI_TARGETASUTF8, 0, pszText); }
    int encode_from_utf8(const char* utf8, char* pszEncode) { return SCI_CMD(SCI_TARGETASUTF8, utf8, pszEncode); }
    int set_encode_length(int nBytes) { return SCI_CMD(SCI_SETLENGTHFORENCODE, nBytes, 0); }


    // Searching and replacing
    // Search Flags - Several of the search routines use flag options, which include a simple regular expression search. Combine the flag options by adding them:
    //  SCFIND_MATCHCASE :  A match only occurs with text that matches the case of the search string.
    //  SCFIND_WHOLEWORD :  A match only occurs if the characters before and after are not word characters.
    //  SCFIND_WORDSTART :  A match only occurs if the character before is not a word character.
    //  SCFIND_REGEXP    :  The search string should be interpreted as a regular expression.
    //  SCFIND_POSIX     :  Treat regular expression in a more POSIX compatible manner by interpreting bare ( and ) for tagged sections rather than \( and \).
    int find_text(int iFlags, TextToFind* ttf) { return SCI_CMD(SCI_FINDTEXT, iFlags, ttf); }
    int search_anchor() { return SCI_CMD(SCI_SEARCHANCHOR, 0, 0); }
    int search_next(int iFlags, TextToFind* ttf) { return SCI_CMD(SCI_SEARCHNEXT, iFlags, ttf); }
    int search_prev(int iFlags, TextToFind* ttf) { return SCI_CMD(SCI_SEARCHPREV, iFlags, ttf); }


    // Overtype
    int set_over_type(bool bOverType) { return SCI_CMD(SCI_SETOVERTYPE, bOverType, 0); }
    int get_over_type() { return SCI_CMD(SCI_GETOVERTYPE, 0, 0); }


    // Cut, copy and paste
    int cut() { return SCI_CMD(SCI_CUT, 0, 0); }
    int copy() { return SCI_CMD(SCI_COPY, 0, 0); }
    int paste() { return SCI_CMD(SCI_PASTE, 0, 0); }
    int clear() { return SCI_CMD(SCI_CLEAR, 0, 0); }
    int can_paste() { return SCI_CMD(SCI_CANPASTE, 0, 0); }
    int copy_range(int nStart, int nEnd) { return SCI_CMD(SCI_COPYRANGE, nStart, nEnd); }
    int copy_text(int nLength, const char* pszText) { return SCI_CMD(SCI_COPYTEXT, nLength, pszText); }
    int copy_allow_line() { return SCI_CMD(SCI_COPYALLOWLINE, 0, 0); }
    int set_paste_convert_endings(bool bConvert) { return SCI_CMD(SCI_SETPASTECONVERTENDINGS, bConvert, 0); }
    int get_paste_convert_endings() { return SCI_CMD(SCI_GETPASTECONVERTENDINGS, 0, 0); }


    // Error Handleing
    // If an error occurs, Scintilla may set an internal error number that can be retrieved with SCI_GETSTATUS. To clear the error status call SCI_SETSTATUS(0). The currently defined statuses are:
    //  SC_STATUS_OK	    0	No failures
    //  SC_STATUS_FAILURE	1	Generic failure
    //  SC_STATUS_BADALLOC	2	Memory is exhausted
    int set_status(int iStatus) { return SCI_CMD(SCI_SETSTATUS, iStatus, 0); }
    int get_status() { return SCI_CMD(SCI_GETSTATUS, 0, 0); }


    // Undo and redo
    int undo() { return SCI_CMD(SCI_UNDO, 0, 0); }
    int can_undo() { return SCI_CMD(SCI_CANUNDO, 0, 0); }
    int empty_undo_buffer() { return SCI_CMD(SCI_EMPTYUNDOBUFFER, 0, 0); }
    int redo() { return SCI_CMD(SCI_REDO, 0, 0); }
    int can_redo() { return SCI_CMD(SCI_CANREDO, 0, 0); }
    int set_undo_collection(bool bCollectUndo) { return SCI_CMD(SCI_SETUNDOCOLLECTION, bCollectUndo, 0); }
    int get_undo_collection() { return SCI_CMD(SCI_GETUNDOCOLLECTION, 0, 0); }
    int begin_undo_action() { return SCI_CMD(SCI_BEGINUNDOACTION, 0, 0); }
    int end_undo_action() { return SCI_CMD(SCI_ENDUNDOACTION, 0, 0); }
    int add_undo_action(int iToken, int iFlags) { return SCI_CMD(SCI_ADDUNDOACTION, iToken, iFlags); }


    // Selection and information
    int get_text_length() { return SCI_CMD(SCI_GETTEXTLENGTH, 0, 0); }
    int get_length() { return SCI_CMD(SCI_GETLENGTH, 0, 0); }
    int get_line_count() { return SCI_CMD(SCI_GETLINECOUNT, 0, 0); }
    int set_first_visible_line(int nDisplayLine) { return SCI_CMD(SCI_SETFIRSTVISIBLELINE, nDisplayLine, 0); }
    int get_first_visible_line() { return SCI_CMD(SCI_GETFIRSTVISIBLELINE, 0, 0); }
    int lines_on_screen() { return SCI_CMD(SCI_LINESONSCREEN, 0, 0); }
    int get_modify() { return SCI_CMD(SCI_GETMODIFY, 0, 0); }
    int set_sel(int nAnchorPos, int nCurrentPos) { return SCI_CMD(SCI_SETSEL, nAnchorPos, nCurrentPos); }
    int goto_pos(int nPos) { return SCI_CMD(SCI_GOTOPOS, nPos, 0); }
    int goto_line(int nLine) { return SCI_CMD(SCI_GOTOLINE, nLine, 0); }
    int set_current_pos(int nPos) { return SCI_CMD(SCI_SETCURRENTPOS, nPos, 0); }
    int get_current_pos() { return SCI_CMD(SCI_GETCURRENTPOS, 0, 0); }
    int set_anchor(int nPos) { return SCI_CMD(SCI_SETANCHOR, nPos, 0); }
    int get_anchor() { return SCI_CMD(SCI_GETANCHOR, 0, 0); }
    int set_sel_start(int nPos) { return SCI_CMD(SCI_SETSELECTIONSTART, nPos, 0); }
    int get_sel_start() { return SCI_CMD(SCI_GETSELECTIONSTART, 0, 0); }
    int set_sel_end(int nPos) { return SCI_CMD(SCI_SETSELECTIONEND, nPos, 0); }
    int get_sel_end() { return SCI_CMD(SCI_GETSELECTIONEND, 0, 0); }
    int set_empty_sel(int nPos) { return SCI_CMD(SCI_SETEMPTYSELECTION, nPos, 0); }
    int select_all() { return SCI_CMD(SCI_SELECTALL, 0, 0); }
    int line_from_pos(int nPos) { return SCI_CMD(SCI_LINEFROMPOSITION, nPos, 0); }
    int pos_from_line(int nLine) { return SCI_CMD(SCI_POSITIONFROMLINE, nLine, 0); }
    int get_line_end_pos(int nLine) { return SCI_CMD(SCI_GETLINEENDPOSITION, nLine, 0); }
    int line_length(int nLine) { return SCI_CMD(SCI_LINELENGTH, nLine, 0); }
    int get_column(int nPos) { return SCI_CMD(SCI_GETCOLUMN, nPos, 0); }
    int find_column(int nLine, int nColumn) { return SCI_CMD(SCI_FINDCOLUMN, nLine, nColumn); }
    int pos_from_point(int x, int y) { return SCI_CMD(SCI_POSITIONFROMPOINT, x, y); }
    int pos_from_point_close(int x, int y) { return SCI_CMD(SCI_POSITIONFROMPOINTCLOSE, x, y); }
    int char_pos_from_point(int x, int y) { return SCI_CMD(SCI_CHARPOSITIONFROMPOINT, x, y); }
    int char_pos_from_point_close(int x, int y) { return SCI_CMD(SCI_CHARPOSITIONFROMPOINTCLOSE, x, y); }
    int x_from_position(int nPos) { return SCI_CMD(SCI_POINTXFROMPOSITION, 0, nPos); }
    int y_from_position(int nPos) { return SCI_CMD(SCI_POINTYFROMPOSITION, 0, nPos); }
    int hide_selection(bool bHide) { return SCI_CMD(SCI_HIDESELECTION, bHide, 0); }
    int get_sel_text(char* pszText) { return SCI_CMD(SCI_HIDESELECTION, 0, pszText); }
    int get_cur_line(int nLength, char* pszText) { return SCI_CMD(SCI_GETCURLINE, nLength, pszText); }
    int selection_is_rectanle() { return SCI_CMD(SCI_SELECTIONISRECTANGLE, 0, 0); }
    int set_selection_mode(int iMode) { return SCI_CMD(SCI_SETSELECTIONMODE, iMode, 0); }
    int get_selection_mode() { return SCI_CMD(SCI_GETSELECTIONMODE, 0, 0); }
    int get_line_sel_start(int nLine) { return SCI_CMD(SCI_GETLINESELSTARTPOSITION, nLine, 0); }
    int get_line_sel_end(int nLine) { return SCI_CMD(SCI_GETLINESELENDPOSITION, nLine, 0); }
    int move_caret_inside_view() { return SCI_CMD(SCI_MOVECARETINSIDEVIEW, 0, 0); }
    int word_start_pos(int nPos, bool bOnlyWordCharacters) { return SCI_CMD(SCI_WORDSTARTPOSITION, nPos, bOnlyWordCharacters); }
    int word_end_pos(int nPos, bool bOnlyWordCharacters) { return SCI_CMD(SCI_WORDENDPOSITION, nPos, bOnlyWordCharacters); }
    int pos_before(int nPos) { return SCI_CMD(SCI_POSITIONBEFORE, nPos, 0); }
    int pos_after(int nPos) { return SCI_CMD(SCI_POSITIONAFTER, nPos, 0); }
    int count_chars(int nStartPos, int nEndPos) { return SCI_CMD(SCI_COUNTCHARACTERS, nStartPos, nEndPos); }
    int text_width(int iStyleNumber, const char* pszText) { return SCI_CMD(SCI_TEXTWIDTH, iStyleNumber, pszText); }
    int text_length(int nLine) { return SCI_CMD(SCI_TEXTHEIGHT, nLine, 0); }
    int choose_caretx() { return SCI_CMD(SCI_CHOOSECARETX, 0, 0); }
    int move_sel_line_up() { return SCI_CMD(SCI_MOVESELECTEDLINESUP, 0, 0); }
    int move_sel_line_down() { return SCI_CMD(SCI_MOVESELECTEDLINESDOWN, 0, 0); }


    int set_ctrl_id(int id) { return SCI_CMD(SCI_SETIDENTIFIER, id, 0); }
    int get_ctrl_id() { return SCI_CMD(SCI_GETIDENTIFIER, 0, 0); }

private:
    static HINSTANCE    _hdll;
    int                 (*_scFunc)(void*,int,int,int);
    void*               _scPtr;
};
